package com.galaxy.service;

import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static java.lang.Boolean.FALSE;

/**
 * @author zgx
 * @date 2025/1/10 11:39
 **/
public class MinioService {

    private final MinioClient minioClient;

    public MinioService(MinioClient minioClient) {
        this.minioClient = minioClient;
    }

    /**
     * 上传文件（会检查桶是否存在，不存在则新建）
     *
     * @param bucketName  桶名称
     * @param objectName  文件名称
     * @param inputStream 文件流
     * @param contentType 类型
     * @param region      区域
     * @return
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public ObjectWriteResponse safeUpload(String bucketName, String objectName, InputStream inputStream, String contentType, String region) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder()
                .bucket(bucketName)
                .region(region)
                .build();

        boolean exist = minioClient.bucketExists(bucketExistsArgs);
        if (FALSE.equals(exist)) {
            MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .region(region)
                    .build();

            minioClient.makeBucket(makeBucketArgs);
        }

        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .contentType(contentType)
                .object(objectName)
                .stream(inputStream, inputStream.available(), -1)
                .region(region)
                .build();

        return minioClient.putObject(putObjectArgs);
    }


    /**
     * 上传文件（会检查桶是否存在，不存在则新建）
     *
     * @param bucketName  桶名称
     * @param objectName  文件名称
     * @param inputStream 文件流
     * @param contentType 类型
     * @return
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public ObjectWriteResponse safeUpload(String bucketName, String objectName, InputStream inputStream, String contentType) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder()
                .bucket(bucketName)
                .build();

        boolean exist = minioClient.bucketExists(bucketExistsArgs);
        if (FALSE.equals(exist)) {
            MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build();

            minioClient.makeBucket(makeBucketArgs);
        }

        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .contentType(contentType)
                .object(objectName)
                .stream(inputStream, inputStream.available(), -1)
                .build();

        return minioClient.putObject(putObjectArgs);
    }


    /**
     * 上传文件
     *
     * @param bucketName  桶名称
     * @param objectName  文件名称
     * @param inputStream 文件流
     * @param contentType 类型
     * @param region      区域
     * @return
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public ObjectWriteResponse upload(String bucketName, String objectName, InputStream inputStream, String contentType, String region) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .contentType(contentType)
                .object(objectName)
                .stream(inputStream, inputStream.available(), -1)
                .region(region)
                .build();

        return minioClient.putObject(putObjectArgs);
    }


    /**
     * 上传文件
     *
     * @param bucketName  桶名称
     * @param objectName  文件名称
     * @param inputStream 文件流
     * @param contentType 类型
     * @return
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public ObjectWriteResponse upload(String bucketName, String objectName, InputStream inputStream, String contentType) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(bucketName)
                .contentType(contentType)
                .object(objectName)
                .stream(inputStream, inputStream.available(), -1)
                .build();

        return minioClient.putObject(putObjectArgs);
    }

    /**
     * 获取文件访问路径
     *
     * @param bucketName 桶名称
     * @param objectName 文件名称
     * @param method     访问方法
     * @param region     区域
     * @param timeUnit   过期时间单位
     * @param duration   过期时间
     * @return 访问路径
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public String getObjectUrl(String bucketName, String objectName, Method method, String region, TimeUnit timeUnit, Integer duration) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .expiry(duration, timeUnit)
                .method(method)
                .object(objectName)
                .region(region)
                .build();

        return minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs);
    }


    /**
     * 获取文件访问路径
     *
     * @param bucketName 桶名称
     * @param objectName 文件名称
     * @param method     访问方法
     * @param region     区域
     * @return 访问路径
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public String getObjectUrl(String bucketName, String objectName, Method method, String region) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .method(method)
                .object(objectName)
                .region(region)
                .build();

        return minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs);
    }


    /**
     * 获取文件访问路径
     *
     * @param bucketName 桶名称
     * @param objectName 文件名称
     * @param method     访问方法
     * @return 访问路径
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public String getObjectUrl(String bucketName, String objectName, Method method) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .method(method)
                .object(objectName)
                .build();

        return minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs);
    }

    /**
     * 下载文件
     *
     * @param bucketName 桶名称
     * @param objectName 文件名称
     * @param region     区域
     * @return 文件流
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public GetObjectResponse getObject(String bucketName, String objectName, String region) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        StatObjectArgs statObjectArgs = StatObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .region(region)
                .build();

        StatObjectResponse statObjectResponse = minioClient.statObject(statObjectArgs);
        if (Objects.isNull(statObjectResponse)) {
            throw new FileNotFoundException("Object not found");
        }

        GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .region(region)
                .build();

        return minioClient.getObject(getObjectArgs);
    }


    /**
     * 下载文件
     *
     * @param bucketName 桶名称
     * @param objectName 文件名称
     * @return 文件流
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public GetObjectResponse getObject(String bucketName, String objectName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        StatObjectArgs statObjectArgs = StatObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();

        StatObjectResponse statObjectResponse = minioClient.statObject(statObjectArgs);
        if (Objects.isNull(statObjectResponse)) {
            throw new FileNotFoundException("Object not found");
        }

        GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();

        return minioClient.getObject(getObjectArgs);
    }


    /**
     * 移除文件
     *
     * @param bucketName 桶名称
     * @param objectName 文件名
     * @param region     区域
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public void removeObject(String bucketName, String objectName, String region) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .region(region)
                .build();

        minioClient.removeObject(removeObjectArgs);
    }

    /**
     * 移除文件
     *
     * @param bucketName 桶名称
     * @param objectName 文件名
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public void removeObject(String bucketName, String objectName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();

        minioClient.removeObject(removeObjectArgs);
    }

}
